iOSアプリからnode.js+Socket.IOと双方向通信する
iOSアプリからUIWebViewなどを介さずにnode.js+Socket.IOと双方向通信するための簡単なサンプルを紹介します。
サーバ側の実装
iOSアプリからnode.js+Socket.IO間で双方向通信するには、socket.IO-objcというライブラリを使用します。 今回はサーバ側には弊社うえじゅん氏が公開している記事で作ったチャットアプリを使用しますので、まずは以下の記事を参考にチャットアプリを作っちゃってください。
Node + Socket.IO で簡単なチャットアプリの作成
チャットアプリの準備が終わったら、早速iOSアプリ側の準備をしましょう。ここからは以下の環境を前提に説明します。
Mac OS X 10.8 Moutain lion
Xcode 4.5.2
iOS SDK 6.0
iOSアプリの実装
サンプルプロジェクトのダウンロード
今回紹介するiOSアプリのソースコードをGitHubにあげてあるのでダウンロードしてください。
hirai-yuki/SocketIOSample
サーバ側を起動した状態で、iOSのサンプルアプリを起動してみてください。ブラウザを立ち上げて「http://localhost:3000」にアクセスしメッセージを送信すると、iOS側の表示が更新されます。逆にiOSアプリからメッセージを送信すると、ブラウザ側の表示が更新されます。
必要なフレームワーク・ライブラリの設定
ここからは要点をしぼって解説します。
必要なライブラリのダウンロード
iOSアプリからnode.js+Socket.IO間で双方向通信するにはsocket.IO-objcと、このライブラリを使用するために必要なSocketRocketとjson-frameworkを使用します。
- socket.IO-objc
- pkyeck/socket.IO-objc
- SocketRocket
- square/SocketRocket
- json-framework
- stig/json-framework
ダウンロードしたライブラリのインポート
ダウンロードしたライブラリをインポートします。各ライブラリで必要なファイルは以下の通りです。
- socket.IO-objc
-
- SocketIO.h
- SocketIO.m
- SocketIOJSONSerialization.h
- SocketIOJSONSerialization.m
- SocketIOPacket.h
- SocketIOPacket.m
- SocketIOTransport.h
- SocketIOTransportWebsocket.h
- SocketIOTransportWebsocket.m
- SocketIOTransportXHR.h
- SocketIOTransportXHR.m
- SocketRocket
- SocketRocket/SocketRocketディレクトリ以下のファイルすべて
- json-framework
- json-framework/Classesディレクトリ以下のファイルすべて
設置場所はどこでも構いませんが、参考までに自分の設置例をのせておきます。
ビルトインのフレームワーク・ライブラリの設定
SocketRocketでは以下のフレームワーク・ライブラリに依存するので、リンクしましょう。
- libicucore.dylib
- CFNetwork.framework
- Security.framework
- Foundation.framework(プロジェクト作成時に既にリンクされているはず)
socket.IO-objcの使い方
SocketIODelegateプロトコル
TableViewController.hでは、socket.IO-objcのデリゲートメソッドを実装するために、SocketIODelegateプロトコルの実装を宣言します。
TableViewController.h
// // TableViewController.h // SocketIOSample // // Created by hirai.yuki on 2013/01/24. // Copyright (c) 2013年 hirai.yuki. All rights reserved. // #import <UIKit/UIKit.h> #import "SocketIO.h" @interface TableViewController : UITableViewController <SocketIODelegate> @end
SocketIODelegateプロトコルでは、以下のメソッドが定義されていますので、適宜実装しておきましょう。
- - (void)socketIODidConnect:(SocketIO *)socket;
- サーバとの接続が確立されたときに実行されるメソッド。
- - (void)socketIODidDisconnect:(SocketIO *)socket disconnectedWithError:(NSError *)error;
- サーバとの接続が切断されたときに実行されるメソッド。
- - (void)socketIO:(SocketIO *)socket didReceiveMessage:(SocketIOPacket *)packet;
- メッセージを受信したときに実行されるメソッド。
- - (void)socketIO:(SocketIO *)socket didReceiveJSON:(SocketIOPacket *)packet;
- JSONを受信したときに実行されるメソッド。
- - (void)socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packet;
- イベントを受信したときに実行されるメソッド。
- - (void)socketIO:(SocketIO *)socket didSendMessage:(SocketIOPacket *)packet;
- メッセージを送信したときに実行されるメソッド。
- - (void)socketIO:(SocketIO *)socket onError:(NSError *)error;
- エラー発生時に実行されるメソッド。
SocketIOインスタンス生成
実際にサーバ側と通信するためのクラスであるSocketIOインスタンスを生成します。インスタンスの生成には、- (id)initWithDelegate:(id
TableViewController.m
... - (void)viewDidLoad { [super viewDidLoad]; ... // socketIOクライアント生成 self.socketIO = [[SocketIO alloc] initWithDelegate:self]; } ...
サーバと接続
サーバとの接続には、SocketIOクラスの以下のメソッドを使用します。
- - (void) connectToHost:(NSString *)host onPort:(NSInteger)port
- - (void) connectToHost:(NSString *)host onPort:(NSInteger)port withParams:(NSDictionary *)params
- - (void) connectToHost:(NSString *)host onPort:(NSInteger)port withParams:(NSDictionary *)params withNamespace:(NSString *)endpoint
... - (void)applicationDidBecomeActive { // localhost:3000に接続開始 [self.socketIO connectToHost:@"localhost" onPort:3000]; } ...
イベントの送信
イベントの送信には、- (void)sendEvent:(NSString *)eventName withData:(NSDictionary *)dataメソッドを使用します。
... - (IBAction)sendEvent:(id)sender { // 文字が入力されていなければ何もしない if (self.formCell.textField.text.length == 0) { return; } // イベント送信 [self.socketIO sendEvent:@"message:send" withData:@{@"message" : self.formCell.textField.text}]; // テキストフィールドをリセット self.formCell.textField.text = @""; } ...
イベントの受信
イベントの受信は、デリゲートメソッドである- (void)socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packetメソッドで定義します。
... - (void)socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packet { NSLog(@"%s", __func__); if ([packet.name isEqualToString:@"message:receive"]) { // メッセージが空でなければ追加 if (packet.args[0][@"message"]) { [self.datas insertObject:packet.args[0][@"message"] atIndex:0]; [self.tableView reloadData]; } } } ...
まとめ
ご覧の通り、socket.IO-objcを使用すればiOSアプリからnode.js+Socket.IO間で双方向通信が簡単に実現できます。まだ業務でゴリゴリ使っていないので何とも言えませんが、はまりどころがあれば報告します!